package com.yantong.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.cache.support.SimpleValueWrapper;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.io.*;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;

/**
 *
 * @author Administrator
 * @date 2016/1/4
 */

@Service
public class LocalRedis implements Cache {

    @Autowired
    private RedisTemplate redisTemplate;

    private String name = "local_cache";

    public RedisTemplate<String, Object> getRedisTemplate() {
        return redisTemplate;
    }

    public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String getName() {
        return this.name;
    }

    @Override
    public Object getNativeCache() {
        return this.redisTemplate;
    }

    @Override
    public ValueWrapper get(Object key) {
        final String keyf = (String) key;
        Object object = null;
        object = redisTemplate.execute((RedisCallback<Object>) connection -> {

            byte[] key1 = keyf.getBytes();
            byte[] value = connection.get(key1);
            if (value == null) {
                return null;
            }
            return toObject(value);

        });
        return (object != null ? new SimpleValueWrapper(object) : null);
    }

    /**
     * 普通缓存获取
     *
     * @param key
     *            键
     * @return 值
     */
    public Object get(String key) {
        return key == null ? null : redisTemplate.opsForValue().get(key);
    }


    @Override
    public <T> T get(Object o, Class<T> aClass) {
        final String keyf = (String) o;
        Object object = null;
        object = redisTemplate.execute((RedisCallback<Object>) connection -> {
            byte[] key1 = keyf.getBytes();
            byte[] value = connection.get(key1);
            if (value == null) {
                return null;
            }
            return toObject(value);

        });
        if (object == null) {
            return null;
        }
        return (T) object;
    }

    @Override
    public <T> T get(Object o, Callable<T> callable) {
        return null;
    }

    @Override
    public void put(Object key, Object value) {
        final String keyf = (String) key;
        final Object valuef = value;
        final long liveTime = 86400;

        redisTemplate.execute((RedisCallback<Long>) connection -> {
            byte[] keyb = keyf.getBytes();
            byte[] valueb = toByteArray(valuef);
            connection.set(keyb, valueb);
            if (liveTime > 0) {
                connection.expire(keyb, liveTime);
            }
            return 1L;
        });
    }

    @Override
    public ValueWrapper putIfAbsent(Object o, Object o1) {
        return null;
    }

    /**
     * ???? : <Object?byte[]>. <br>
     * <p>
     * <??÷??????>
     * </p>
     *
     * @param obj
     * @return
     */
    private byte[] toByteArray(Object obj) {
        byte[] bytes = null;
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        try {
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(obj);
            oos.flush();
            bytes = bos.toByteArray();
            oos.close();
            bos.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        return bytes;
    }

    /**
     * ???? : <byte[]?Object>. <br>
     * <p>
     * <??÷??????>
     * </p>
     *
     * @param bytes
     * @return
     */
    private Object toObject(byte[] bytes) {
        Object obj = null;
        ByteArrayInputStream bis = null;
        ObjectInputStream ois = null;
        try {
            bis = new ByteArrayInputStream(bytes);
            ois = new ObjectInputStream(bis);
            obj = ois.readObject();
        } catch (IOException ex) {
            ex.printStackTrace();
        } catch (ClassNotFoundException ex) {
            ex.printStackTrace();
        }finally {
 			try {
 				if (bis != null) {
 					bis.close();
 				}
 				if (ois != null) {
 					ois.close();
 				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
        return obj;
    }

    @Override
    public void evict(Object key) {

        final String keyf = (String) key;
        redisTemplate.execute((RedisCallback<Long>) connection -> {
            return connection.del(keyf.getBytes());
        });
    }

    @Override
    public void clear() {

        redisTemplate.execute((RedisCallback<String>) connection -> {
            connection.flushDb();
            return "ok";
        });
    }

    public Integer getNum(String key) {
        if (key == null) {
            return null;
        }
        Object obj = redisTemplate.opsForValue().get(key);
        if (obj == null) {
            return null;
        }
        return (Integer) obj;
    }

    public Integer getCacheVersion(String key) {
        if (key == null) {
            return 0;
        }
        Object obj = redisTemplate.opsForValue().get(key);
        if (obj == null) {
            return null;
        }
        return (Integer) obj;
    }
    /**
     * 设置一个缓存
     * @param key
     * @param value
     */
    public void set(String key ,Object value) {
         redisTemplate.opsForValue().set(key, value);
    }

    /**
     * 设置一个缓存 过期时间天
     * @param key
     * @param value
     */
    public void setByDay(String key ,Object value,Integer day) {
         redisTemplate.opsForValue().set(key, value,day,TimeUnit.DAYS);
    }
    
    /**
     * 设置一个缓存过期时间 时
     * @param key
     * @param value
     */
    public void setByHours(String key ,Object value,Integer hour) {
         redisTemplate.opsForValue().set(key, value,hour,TimeUnit.HOURS);
    }
    
    /**
     * 设置一个缓存过期时间 分
     * @param key
     * @param value
     */
    public void setByMinute(String key ,Object value,Integer Minute) {
         redisTemplate.opsForValue().set(key, value,Minute,TimeUnit.MINUTES);
    }

    /**
     * 设置一个缓存
     * @param key
     * @param value
     */
    public void set(String key ,Object value,long time,TimeUnit timeUnit) {
        redisTemplate.opsForValue().set(key, value,time,timeUnit);
    }
    
    public long increamNum(String key ,long size) {
        return redisTemplate.opsForValue().increment(key, size);
    }
    
    /**
     * 按键删除一个缓存
     * @param key
     */
    public void delByKey(String key) {
        redisTemplate.delete(key);
   }
}
